{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/sharedata/mdy/miniforge/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import triton\n",
    "import triton.language as tl\n",
    "from transformers.models.llama.modeling_llama import LlamaRMSNorm\n",
    "import os\n",
    "os.environ['TRITON_PRINT_AUTOTUNING'] = '1'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- RMSNorm的实现，写了详细的求导过程，帮助理解\n",
    "- 对比torch内置和hf-llama的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# core"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1 RMSNorm前向传播\n",
    "#### x是一个N维向量，“*” 是element-wise的乘法\n",
    "$$y=RMSNorm(x) = \\frac{x}{\\sqrt{\\sum_{i=1}^N x_i^2 + eps}} * weight$$\n",
    "### 2 反向传播推导\n",
    "#### $\\frac{\\partial L}{\\partial y}$是Loss对y的导数\n",
    "#### $\\frac{\\partial L}{\\partial x}$是Loss对x的导数\n",
    "#### $\\frac{\\partial L}{\\partial w}$是L对w的导数\n",
    "#### $\\hat{x} = \\frac{x}{\\sqrt{\\sum_{i=1}^N x_i^2 + eps}}$\n",
    "#### $std = \\sqrt{\\sum_{i=1}^N x_i^2 + eps}$\n",
    "### 2.1 求dw\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\frac{\\partial L}{\\partial w_i} &= \\sum_{j=1}^N \\frac{\\partial y_j}{\\partial w_i} \\frac{\\partial L}{\\partial y_j}\\\\\n",
    "&= \\frac{\\partial y_i}{\\partial w_i} \\frac{\\partial L}{\\partial y_i}\\\\\n",
    "&= \\hat{x_{i}} \\frac{\\partial L}{\\partial y_i}\n",
    "\\end{aligned}$$\n",
    "#### 推广到向量表示\n",
    "$$\\frac{\\partial L}{\\partial w} = \\hat{x} * \\frac{\\partial L}{\\partial y}$$\n",
    "### 2.2 求dx\n",
    "$$\\frac{\\partial L}{\\partial x_i} = \\sum_{j=1}^N \\frac{\\partial y_j}{\\partial x_i} \\frac{\\partial L}{\\partial y_j}$$\n",
    "#### 先求$\\frac{\\partial y_j}{\\partial x_i}$, 下面根据乘法求导法则和链式法则, $I(i==j)$是示性函数,i=j为1否则为0\n",
    "$$\\begin{aligned}\n",
    "\\frac{\\partial y_j}{\\partial x_i} &= \\frac{I(i==j)}{std}*w_j + x_j * (-\\frac{1}{2})*\\frac{1}{std^3}*\\frac{1}{N}*2x_i *w_j\\\\\n",
    "&= (I(i==j)*w_j -\\frac{1}{N}*\\hat{x_i}*\\hat{x_j}*w_j)/std\\\\\n",
    "\\end{aligned}$$\n",
    "### 带进去,第2行括号里改成内积形式\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\frac{\\partial L}{\\partial x_i} &= \\sum_{j=1}^N \\frac{\\partial y_j}{\\partial x_i} \\frac{\\partial L}{\\partial y_j}\\\\\n",
    "&= (w_j * \\frac{\\partial L}{\\partial y_i} -\\frac{\\hat{x_i}}{N}* (\\sum_{j=1}^N \\hat{x_j}*w_j*\\frac{\\partial L}{\\partial y_j}))/std\\\\\n",
    "&= (w_j * \\frac{\\partial L}{\\partial y_i} -\\frac{\\hat{x_i}}{N}* (\\hat{x^T}(w * \\frac{\\partial L}{\\partial y})))/std\n",
    "\\end{aligned}$$\n",
    "#### 推广到向量表示\n",
    "$$\\frac{\\partial L}{\\partial x} = (w * \\frac{\\partial L}{\\partial y} -\\frac{\\hat{x}}{N}* (\\hat{x^T}(w * \\frac{\\partial L}{\\partial y})))/std$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "@triton.autotune([triton.Config({}, num_warps=nw)\n",
    "                  for nw in [1, 2, 4, 8, 16]],\n",
    "                  key=['BLOCK_N'])\n",
    "@triton.jit\n",
    "def _rmsnorm_fwd(X, Y, W, RMS_STD, eps,\n",
    "                 row_stride,\n",
    "                 N,\n",
    "                 BLOCK_N:tl.constexpr,):\n",
    "    row_id = tl.cast(tl.program_id(0), tl.int64)\n",
    "    cols = tl.arange(0, BLOCK_N)\n",
    "    mask = cols < N\n",
    "\n",
    "    x = tl.load(X + row_id * row_stride + cols, mask=mask, other=0.).to(tl.float32)\n",
    "    w = tl.load(W + cols, mask=mask, other=0.).to(tl.float32)\n",
    "\n",
    "    rms_std = tl.sqrt(tl.sum(x * x) / N + eps)\n",
    "    x_hat = x / rms_std\n",
    "    y = x_hat * w\n",
    "\n",
    "    tl.store(Y + row_id * row_stride + cols, y, mask=mask)\n",
    "    tl.store(RMS_STD+row_id, rms_std)\n",
    "\n",
    "@triton.autotune([triton.Config({}, num_warps=nw)\n",
    "                  for nw in [1, 2, 4, 8, 16]],\n",
    "                  key=['BLOCK_N'])\n",
    "@triton.jit\n",
    "def _rmsnorm_bwd_dx_fused(DX, DY, DW, X, W, RMS_STD,\n",
    "                        row_stride,\n",
    "                        M, N, BLOCK_N:tl.constexpr):\n",
    "    start_id = tl.cast(tl.program_id(0), tl.int64)\n",
    "    cols = tl.arange(0, BLOCK_N)\n",
    "    mask = cols < N\n",
    "    dw = tl.zeros([BLOCK_N,], dtype=tl.float32)\n",
    "    for row_id in range(start_id, M, tl.num_programs(0)):\n",
    "        x = tl.load(X + row_id * row_stride + cols, mask=mask, other=0.).to(tl.float32)\n",
    "        w = tl.load(W + cols, mask=mask, other=0.)\n",
    "        dy = tl.load(DY + row_id * row_stride + cols, mask=mask, other=0.).to(tl.float32)\n",
    "        rms_std = tl.load(RMS_STD+row_id)\n",
    "\n",
    "        x_hat = x / rms_std\n",
    "        wdy = w * dy\n",
    "        dx = (wdy - (x_hat / N) * tl.sum(x_hat * wdy)) / rms_std\n",
    "        tl.store(DX + row_id * row_stride + cols, dx, mask=mask)\n",
    "\n",
    "        dw += x_hat * dy\n",
    "    tl.store(DW + start_id * row_stride + cols, dw, mask=mask)\n",
    "\n",
    "\n",
    "class _TritronRMSNorm(torch.autograd.Function):\n",
    "\n",
    "    @staticmethod\n",
    "    def forward(ctx, hidden_state, weight, eps):\n",
    "        ctx.input_shape = hidden_state.shape\n",
    "        output = torch.empty_like(hidden_state)\n",
    "        hidden_state = hidden_state.reshape(-1, ctx.input_shape[-1])\n",
    "        M,N = hidden_state.shape\n",
    "        BLOCK_N = triton.next_power_of_2(N)\n",
    "        rms_std = torch.empty(M, dtype=torch.float32, device=hidden_state.device)\n",
    "        _rmsnorm_fwd[(M, )](hidden_state, output, weight, rms_std, eps,\n",
    "                            hidden_state.stride(0),\n",
    "                            N,\n",
    "                            BLOCK_N,\n",
    "                            )\n",
    "        ctx.save_for_backward(hidden_state, weight, rms_std)\n",
    "        return output\n",
    "    \n",
    "    @staticmethod\n",
    "    def backward(ctx, dy):\n",
    "        # dy = dy.contiguous()\n",
    "        hidden_state, weight, rms_std = ctx.saved_tensors\n",
    "        hidden_state = hidden_state.reshape(-1, hidden_state.shape[-1])\n",
    "        M,N = hidden_state.shape\n",
    "        BLOCK_N = triton.next_power_of_2(N)\n",
    "\n",
    "        NUM_SMS = torch.cuda.get_device_properties('cuda').multi_processor_count\n",
    "        dw = torch.empty(NUM_SMS, N, dtype=torch.float32, device=weight.device)\n",
    "        dx = torch.empty_like(dy)\n",
    "        \n",
    "        _rmsnorm_bwd_dx_fused[(NUM_SMS,)](dx, dy, dw, hidden_state, weight, rms_std, \n",
    "                 hidden_state.stride(0),\n",
    "                 M, N, BLOCK_N\n",
    "                 )\n",
    "        dw = dw.sum(0).to(weight.dtype)\n",
    "        return dx.view(*ctx.input_shape), dw, None\n",
    "\n",
    "triton_rmsnorm = _TritronRMSNorm.apply\n",
    "class TritonRMSNorm(torch.nn.Module):\n",
    "    def __init__(self, hidden_size, eps=1e-6):\n",
    "        super().__init__()\n",
    "        self.weight = torch.nn.Parameter(torch.ones(hidden_size))\n",
    "        self.eps = eps\n",
    "    \n",
    "    def forward(self, hidden_state):\n",
    "        return triton_rmsnorm(hidden_state, self.weight, self.eps)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 精度测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "dim = 3585\n",
    "dtype = torch.bfloat16\n",
    "rmsnorm_triton = TritonRMSNorm(dim, eps=1e-6).cuda().to(dtype)\n",
    "rmsnorm_llama = LlamaRMSNorm(dim, eps=1e-6).cuda().to(dtype)\n",
    "rmsnorm_llama.weight.data = torch.randn(dim).cuda().to(dtype)\n",
    "rmsnorm_triton.weight.data.copy_(rmsnorm_llama.weight.data)\n",
    "x1 = torch.randn(8192 * 2, dim).cuda().to(dtype)\n",
    "x2 = torch.randn(8192 * 2, dim).cuda().to(dtype)\n",
    "x2.data.copy_(x1)\n",
    "x1.requires_grad = True\n",
    "x2.requires_grad = True\n",
    "dy = torch.ones_like(x1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "triton vs hf-llama\n",
      "False 0.0625\n",
      "False 0.015625\n",
      "False 2.0\n"
     ]
    }
   ],
   "source": [
    "if x1.grad is not None:\n",
    "    x1.grad.zero_()\n",
    "    rmsnorm_llama.weight.grad.zero_()\n",
    "y1 = rmsnorm_llama(x1)\n",
    "y1.backward(dy)\n",
    "\n",
    "if x2.grad is not None:\n",
    "    x2.grad.zero_()\n",
    "    rmsnorm_triton.weight.grad.zero_()\n",
    "y2 = rmsnorm_triton(x2)\n",
    "y2.backward(dy)\n",
    "\n",
    "\n",
    "print('triton vs hf-llama')\n",
    "print(torch.allclose(y1, y2, 0.0001, 0.0001), (y1 - y2).abs().max().item())\n",
    "print(torch.allclose(x1.grad, x2.grad, 0.0001, 0.0001), (x1.grad - x2.grad).abs().max().item())\n",
    "print(torch.allclose(rmsnorm_llama.weight.grad, rmsnorm_triton.weight.grad, 0.0001, 0.0001),\n",
    "      (rmsnorm_llama.weight.grad - rmsnorm_triton.weight.grad).abs().max().item())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Forward benchmark"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bs: 8, seq_len: 1024\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 1.02s; best config selected: num_warps: 2, num_ctas: 1, num_stages: 2, num_buffers_warp_spec: 0, num_consumer_groups: 0, reg_dec_producer: 0, reg_inc_consumer: 0, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 1.09s; best config selected: num_warps: 4, num_ctas: 1, num_stages: 2, num_buffers_warp_spec: 0, num_consumer_groups: 0, reg_dec_producer: 0, reg_inc_consumer: 0, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 1.27s; best config selected: num_warps: 4, num_ctas: 1, num_stages: 2, num_buffers_warp_spec: 0, num_consumer_groups: 0, reg_dec_producer: 0, reg_inc_consumer: 0, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 1.75s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, num_buffers_warp_spec: 0, num_consumer_groups: 0, reg_dec_producer: 0, reg_inc_consumer: 0, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 3.45s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, num_buffers_warp_spec: 0, num_consumer_groups: 0, reg_dec_producer: 0, reg_inc_consumer: 0, maxnreg: None;\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSNorm:\n",
      "        dim  Triton-RMSNorm  HF-LlamaRMSNorm  torch.nn.RMSNorm\n",
      "0    1024.0       15.973479       140.719354         69.278598\n",
      "1    2048.0       23.050833       260.161459        132.337272\n",
      "2    3072.0       30.750984       372.297883        187.396333\n",
      "3    4096.0       39.101072       483.878046        241.677880\n",
      "4    5120.0       49.609777       595.513463        295.899093\n",
      "5    6144.0       55.496704       706.142485        349.312544\n",
      "6    7168.0       62.357385       816.811919        403.124720\n",
      "7    8192.0       71.044594       938.829303        475.697428\n",
      "8    9216.0       93.727320      1053.509593        532.463908\n",
      "9   10240.0       99.560834      1159.850717        582.645059\n",
      "10  11264.0      103.839926      1272.749543        638.487220\n",
      "11  12288.0      107.983924      1378.393769        689.254224\n",
      "12  13312.0      113.869652      1491.793633        743.923187\n",
      "13  14336.0      119.349420      1598.220587        794.704378\n",
      "14  15360.0      126.597047      1712.006450        849.812031\n",
      "15  16384.0      132.972926      1820.690989        901.305020\n"
     ]
    }
   ],
   "source": [
    "\n",
    "@triton.testing.perf_report(\n",
    "    triton.testing.Benchmark(\n",
    "        x_names=['dim'],  # argument names to use as an x-axis for the plot\n",
    "        x_vals=[1024 * i for i in range(1, 16+1)],  # different possible values for `x_name`\n",
    "        line_arg='provider',  # argument name whose value corresponds to a different line in the plot\n",
    "        line_vals=['Triton-RMSNorm', 'HF-LlamaRMSNorm', 'torch.nn.RMSNorm'],  # possible values for `line_arg``\n",
    "        line_names=[\n",
    "            \"Triton-RMSNorm\",\n",
    "            \"HF-LlamaRMSNorm\",\n",
    "            \"torch.nn.RMSNorm\"\n",
    "        ],  # label name for the lines\n",
    "        styles=[('blue', '-'), ('green', '-'), ('orange', '-')],  # line styles\n",
    "        ylabel=\"ms\",  # label name for the y-axis\n",
    "        plot_name=\"RMSNorm\",  # name for the plot. Used also as a file name for saving the plot.\n",
    "        args={'seq_len': 1024, 'bs': 8}\n",
    "        # args={'bs': 2, 'num_head': 32, 'rope_head_dim': 32, \n",
    "        #       'nope_head_dim': 64, 'kv_lora_rank': 256},  # values for function arguments not in `x_names` and `y_name`\n",
    "    ))\n",
    "def benchmark(bs, seq_len, dim, provider):\n",
    "    device = torch.device('cuda')\n",
    "    dtype = torch.float16\n",
    "    tensor = torch.randn(bs, seq_len, dim).to(device).to(dtype)\n",
    "    stream = torch.cuda.Stream()\n",
    "    torch.cuda.set_stream(stream)\n",
    "    if provider == 'HF-LlamaRMSNorm':\n",
    "        rmsnorm_llama = LlamaRMSNorm(dim).cuda().to(dtype)\n",
    "        ms = triton.testing.do_bench(lambda: rmsnorm_llama(tensor))\n",
    "    if provider == 'Triton-RMSNorm':\n",
    "        rmsnorm_triton = TritonRMSNorm(dim).cuda().to(dtype)\n",
    "        ms = triton.testing.do_bench(lambda: rmsnorm_triton(tensor))\n",
    "    if provider == 'torch.nn.RMSNorm':\n",
    "        rmsnorm_triton = torch.nn.RMSNorm(dim).cuda().to(dtype)\n",
    "        ms = triton.testing.do_bench(lambda: rmsnorm_triton(tensor))\n",
    "\n",
    "    return ms * 1e3\n",
    "print(f'bs: {8}, seq_len: {1024}')\n",
    "benchmark.run(show_plots=True, print_data=True)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Backward benchmark"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bs: 8, seq_len: 1024\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 0.62s; best config selected: num_warps: 1, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_bwd_dx_fused finished after 0.60s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 0.58s; best config selected: num_warps: 4, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_bwd_dx_fused finished after 0.60s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 0.59s; best config selected: num_warps: 4, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_bwd_dx_fused finished after 0.62s; best config selected: num_warps: 16, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 0.60s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_bwd_dx_fused finished after 0.67s; best config selected: num_warps: 16, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_fwd finished after 0.64s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, maxnreg: None;\n",
      "Triton autotuning for function _rmsnorm_bwd_dx_fused finished after 0.83s; best config selected: num_warps: 8, num_ctas: 1, num_stages: 2, maxnreg: None;\n"
     ]
    },
    {
     "data": {
      "image/png": "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nT9/Xq1cuVI5OTmpmTNnFvi2bty4UX3wwQdq1apVClCrV682O59X7dq9e7eytLRU06ZNU3///bcaM2aMsra2VkeOHMmTtsbGxqrmzZur7777Tp04cUJFRkaq5557TtWpU8fsGgWhrY/6O820atUqVbNmTeXr66tmzJhR4Nr5OG09c+aMcnd3VyNHjlR//PGHOnPmjFq7dq2Kjo421SnIn8mSEBUCMTExClA7d+5UShk/jKytrdXKlStNdY4fP64AFRkZqZQy/uJbWFioqKgoU505c+YoFxcXlZKSopRSatSoUapq1apmr9W1a1cVFBSU200yc+fOHfXMM8+oiIgI1ahRI1NCVJjaGRYWpl544YUHnjcYDMrb21t98sknprLY2Fhla2urvv32W6WUUn///bcC1P79+011Nm3apHQ6nbp69apSSqnZs2erYsWKmdqe+doVK1bM6SY9UJs2bVTfvn3Nyjp16qR69uyplCo8bb33CyUv2/Xaa6+pNm3amMVTv3599cYbb+RoGzM9LFHItG/fPgWoixcvKqUKZlsf1M4rV66okiVLqqNHj6oyZcqYJUQFsZ1KZd/Wrl27ql69ej3wOQX9M1mGzAqBuLg4ANzd3QE4ePAgaWlpNG/e3FSnUqVKlC5dmsjISAAiIyOpXr06Xl5epjpBQUHo9XqOHTtmqnP3NTLrZF4jrwwZMoQ2bdrcF0thaue6deuoW7cur776Kp6entSuXZuvv/7adP78+fNERUWZxenq6kr9+vXN2urm5kbdunVNdZo3b46FhQV79+411XnppZewsbEx1QkKCuLkyZPcvn07t5sJwPPPP8/WrVs5deoUAH/99Re//fYbrVq1AgpXW++Wl+3KD7/T94qLi0On0+Hm5gYUnrYaDAaCg4MZOXIkVatWve98YWrnhg0bqFChAkFBQXh6elK/fn2zYbWC/pksCVEBZzAYGDZsGA0bNqRatWoAREVFYWNjY/rgyeTl5UVUVJSpzt2/kJnnM889rI5erycpKSk3mnOfFStW8McffzBlypT7zhWmdp47d445c+bwzDPPsGXLFgYNGsRbb73FokWLzGLNLs672+Hp6Wl23srKCnd39yd6P3Lbe++9R7du3ahUqRLW1tbUrl2bYcOG0bNnT7M4CkNb75aX7XpQHS3aDcZ5JWFhYXTv3t20yWdhaev//d//YWVl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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSNorm:\n",
      "        dim  Triton-RMSNorm  HF-LlamaRMSNorm  torch.nn.RMSNorm\n",
      "0    1024.0       85.625067       318.088442        193.955302\n",
      "1    2048.0       90.717226       567.630470        337.140858\n",
      "2    3072.0      101.451367       802.493334        464.212447\n",
      "3    4096.0      110.647194      1035.443187        590.929806\n",
      "4    5120.0      140.789628      1268.996954        717.392206\n",
      "5    6144.0      147.875950      1503.264666        843.998432\n",
      "6    7168.0      155.686468      1738.743424        970.858216\n",
      "7    8192.0      159.418300      1983.961701       1114.919901\n",
      "8    9216.0      210.956857      2219.896317       1242.234945\n",
      "9   10240.0      218.391374      2448.610783       1366.470575\n",
      "10  11264.0      225.862399      2688.612938       1494.191885\n",
      "11  12288.0      234.557763      2920.977592       1621.744514\n",
      "12  13312.0      242.942020      3155.173779       1748.531938\n",
      "13  14336.0      249.332204      3384.104013       1872.486711\n",
      "14  15360.0      256.566614      3621.147871       1999.727964\n",
      "15  16384.0      263.585329      3858.230591       2122.587919\n"
     ]
    }
   ],
   "source": [
    "\n",
    "@triton.testing.perf_report(\n",
    "    triton.testing.Benchmark(\n",
    "        x_names=['dim'],  # argument names to use as an x-axis for the plot\n",
    "        x_vals=[1024 * i for i in range(1, 16+1)],  # different possible values for `x_name`\n",
    "        line_arg='provider',  # argument name whose value corresponds to a different line in the plot\n",
    "        line_vals=['Triton-RMSNorm', 'HF-LlamaRMSNorm', 'torch.nn.RMSNorm'],  # possible values for `line_arg``\n",
    "        line_names=[\n",
    "            \"Triton-RMSNorm\",\n",
    "            \"HF-LlamaRMSNorm\",\n",
    "            \"torch.nn.RMSNorm\"\n",
    "        ],  # label name for the lines\n",
    "        styles=[('blue', '-'), ('green', '-'), ('orange', '-')],  # line styles\n",
    "        ylabel=\"ms\",  # label name for the y-axis\n",
    "        plot_name=\"RMSNorm\",  # name for the plot. Used also as a file name for saving the plot.\n",
    "        args={'seq_len': 1024, 'bs': 8}\n",
    "    ))\n",
    "def benchmark(bs, seq_len, dim, provider):\n",
    "    device = torch.device('cuda')\n",
    "    dtype = torch.float16\n",
    "    tensor = torch.randn(bs, seq_len, dim).to(device).to(dtype)\n",
    "    tensor.requires_grad_(True)\n",
    "    stream = torch.cuda.Stream()\n",
    "    torch.cuda.set_stream(stream)\n",
    "    dy = torch.ones_like(tensor)\n",
    "    if provider == 'HF-LlamaRMSNorm':\n",
    "        rmsnorm_llama = LlamaRMSNorm(dim, eps=1e-6).cuda().to(dtype)\n",
    "        y = rmsnorm_llama(tensor)\n",
    "        ms = triton.testing.do_bench(lambda: y.backward(dy,retain_graph=True), grad_to_none=[tensor])\n",
    "\n",
    "    if provider == 'Triton-RMSNorm':\n",
    "        rmsnorm_triton = TritonRMSNorm(dim, eps=1e-6).cuda().to(dtype)\n",
    "        y = rmsnorm_triton(tensor)\n",
    "        ms = triton.testing.do_bench(lambda: y.backward(dy,retain_graph=True), grad_to_none=[tensor])\n",
    "    \n",
    "    if provider == 'torch.nn.RMSNorm':\n",
    "        rmsnorm_triton = torch.nn.RMSNorm(dim, eps=1e-6).cuda().to(dtype)\n",
    "        y = rmsnorm_triton(tensor)\n",
    "        ms = triton.testing.do_bench(lambda: y.backward(dy,retain_graph=True), grad_to_none=[tensor])\n",
    "    \n",
    "\n",
    "    return ms * 1e3\n",
    "print(f'bs: {8}, seq_len: {1024}')\n",
    "benchmark.run(show_plots=True, print_data=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "RMSNorm((5,), eps=None, elementwise_affine=True)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.nn.RMSNorm(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
